%{
	#include "scanner.h"
	#include <string>
	#include <vector>
	#include <iostream>

	extern unsigned line;

	void yyerror (char *s) { std::cerr << "Error on line " << line << ": " << s << std::endl; }

	class topic {
		public:
			std::string name;
			std::string description;
			std::string notes;

			void addAlso(const std::string& a) { also.push_back(a); }
			std::vector<std::string> also;
	};

	class command: public topic {
		public:
			void addSynopsis(int num, const std::string& s) { if (num > synopses.size()) synopses.resize(num); synopses[num-1] = s; }
			std::vector<std::string> synopses;

			void addDescription(int num, const std::string& d) { if (num > descriptions.size()) descriptions.resize(num); descriptions[num-1] = d; } 
			std::vector<std::string> descriptions;
	};

	std::vector<command> commands;
	std::vector<topic> topics;
	topic currentTopic;
	command currentCommand;
%}

%start commands_and_topics

%error-verbose

%union {
	int				intVal;
	const char*		strVal;
}

%token	TOKEN_COMMAND
%token	TOKEN_TOPIC
%token	TOKEN_NAME
%token	TOKEN_SYNOPSIS
%token	TOKEN_DESCRIPTION
%token  TOKEN_NOTES
%token  TOKEN_SEEALSO
%token  TOKEN_UNKNOWN "unknown character"

%token  TOKEN_END 0 "end of file"

%token <intVal> TOKEN_NUMBER
%token <strVal>	TOKEN_STRING

%type <strVal> name
%type <strVal> notes
%type <strVal> description

%%

commands_and_topics:
		commands_and_topics command
		| commands_and_topics topic
		| /* nothing */
		;

command:
		TOKEN_COMMAND commandparams { commands.push_back(currentCommand); currentCommand = command(); }
		;

commandparams:
		commandparams commandparam
		| /* nothing */
		;

commandparam:
		name { currentCommand.name = std::string($1); }
		| description { currentCommand.description = std::string($1); }
		| command_synopsis
		| command_description
		| notes { currentCommand.notes = std::string($1); }
		| command_seealso
		;

topic:
		TOKEN_TOPIC topicparams { topics.push_back(currentTopic); currentTopic = topic(); }
		;

topicparams:
		topicparams topicparam
		| /* nothing */
		;

topicparam:
		name { currentTopic.name = std::string($1); }
		| description { currentTopic.description = std::string($1); }
		| notes { currentTopic.notes = std::string($1); }
		| topic_seealso
		;

name:
		TOKEN_NAME TOKEN_STRING { $$ = $2; }
		;

command_synopsis:
		TOKEN_SYNOPSIS TOKEN_NUMBER TOKEN_STRING { currentCommand.addSynopsis($2, std::string($3)); }
		;

command_description:
		TOKEN_DESCRIPTION TOKEN_NUMBER TOKEN_STRING { currentCommand.addDescription($2, std::string($3)); }
		;

description:
		TOKEN_DESCRIPTION TOKEN_STRING { $$ = $2; }
		;

notes:
		TOKEN_NOTES TOKEN_STRING { $$ = $2; }
		;

topic_seealso:
		TOKEN_SEEALSO also_topics
		;

command_seealso:
		TOKEN_SEEALSO also_commands
		;

also_commands:
		also_commands TOKEN_STRING { currentCommand.addAlso(std::string($2)); }
		| /* nothing */
		;

also_topics:
		also_topics TOKEN_STRING { currentTopic.addAlso(std::string($2)); }
		| /* nothing */
		;

%%


